// package 数据存储层
package dao

import (
	"fmt"
	"math/rand"
	"osiris/db"
	"osiris/logger"
	"osiris/model"
)

// GetAccountByAddr 根据账户地址查找账户信息
//
//	@param addrStr
//	@return model.AccountModel
//	@return error
func GetAccountByAddr(addrStr string) (model.AccountModel, error) {
	var accountModel model.AccountModel
	err := db.MySQL.Where("addr = ?", addrStr).First(&accountModel).Error
	return accountModel, err
}

// GetAccountByID 根据自增ID查找账户信息
//
//	@param id
//	@return model.AccountModel
//	@return error
func GetAccountByID(id uint) (model.AccountModel, error) {
	var accountModel model.AccountModel
	err := db.MySQL.Where("ID = ?", id).First(&accountModel).Error
	return accountModel, err
}

// GetAllAddrs 返回peers表中所有数据
//
//	@return []model.PeerModel
//	@return error
func GetAllAccount() ([]model.AccountModel, error) {
	var accountModels []model.AccountModel
	err := db.MySQL.Find(&accountModels).Error
	return accountModels, err
}

// AddAccountByModel 通过model存储账户信息，包括：StateLeaf要用到的addr（key）, asset(value1), nonce(value2), maxNonce(value2)
//
//	@param model
//	@return error
func AddAccountByModel(model model.AccountModel) error {
	err := db.MySQL.Create(&model).Error
	if err != nil {
		logger.Error(map[string]interface{}{"[dao] [Add account by model]": err})
		return err
	}

	logger.Info(map[string]interface{}{"[dao] [Add account by model]": "success"})
	return nil
}

// GetRandomAccount 随机读取accounts数据表中某一个账户数据（用于测试，随机生成transform交易）
//
//	@return model.AccountModel
//	@return error
func GetRandomAccount() (model.AccountModel, error) {
	var count int64
	accountModel := model.AccountModel{}
	err1 := db.MySQL.Table(accountModel.TableName()).Count(&count).Error
	if err1 != nil {
		logger.Error(map[string]interface{}{"[dao] [Get Random Account] count table accounts": err1})
		return accountModel, err1
	}

	var err2 error
	randRow := rand.Int63n(count) + 1
	accountModel, err2 = GetAccountByID(uint(randRow))
	if err2 != nil {
		logger.Error(map[string]interface{}{fmt.Sprintf("[dao] [Get Random Account] get account in row %d", randRow): err2})
		return accountModel, err2
	}

	logger.Debug(map[string]interface{}{"[dao] [Get Random Account]": fmt.Sprintf("get account in row %d (total: %d)", randRow, count)})
	return accountModel, nil
}

func UpdateAccount(addrStr string, asset int64, coinSince int64, nonce int64) (int64, error) {
	result := db.MySQL.Model(&model.AccountModel{}).Where("addr = ?", addrStr).Select("Asset", "CoinSince", "Nonce").Updates(
		model.AccountModel{
			Asset:     asset,
			CoinSince: coinSince,
			Nonce:     nonce,
		},
	)

	return result.RowsAffected, result.Error
}

// TruncateAccounts 硬删除accounts表中的所有数据
//
//	@return error
func TruncateAccounts() error {
	return db.MySQL.Exec(fmt.Sprintf("truncate %s", model.AccountModel{}.TableName())).Error
}

// SaveAccount Save update value in database, if the value doesn't have primary key, will insert it
// DO NOT RECOMMAND HERE! USE UPDATE INSTEAD
//
//	@param model model.AccountModel
//	@return error
func SaveAccount(model model.AccountModel) error {
	err := db.MySQL.Where("addr = ?", model.Addr).Save(&model).Error
	return err
}

func DeleteAccount(accountAddrStr string) error {
	err := db.MySQL.Delete(&model.AddrModel{}, "addr = ?", accountAddrStr).Error
	return err
}
